package main

import (
	"net"
	"strings"
)

type User struct {
	Name   string
	Addr   string
	C      chan string
	conn   net.Conn
	Server *Server
}

// create a user
func NewUser(conn net.Conn, server *Server) *User {
	// new user
	user := &User{
		Name:   conn.RemoteAddr().String(),
		Addr:   conn.RemoteAddr().String(),
		C:      make(chan string),
		conn:   conn,
		Server: server,
	}
	// start ListenMessage
	go user.ListenMessage()

	return user
}

// user online
func (this *User) Online() {

	// add user to onlineMap
	this.Server.mapLock.Lock()
	this.Server.OnlineMap[this.Name] = this
	this.Server.mapLock.Unlock()

	// broadcast user online message
	this.Server.Broadcast(this, "is online")
}

// user offline
func (this *User) Offline() {

	// delete user in onlineMap
	this.Server.mapLock.Lock()
	delete(this.Server.OnlineMap, this.Name)
	this.Server.mapLock.Unlock()

	// broadcast user offline message
	this.Server.Broadcast(this, "is offline")
}

// send message to client
func (this *User) SendMsg(msg string) {
	// this.Server.Message <- msg// will be broadcast automactically
	this.conn.Write([]byte(msg))
}

// user handle message
func (this *User) DoMessage(msg string) {
	if msg == "who" {
		// check online users
		this.Server.mapLock.Lock()
		for _, u := range this.Server.OnlineMap {
			onlineMsg := "[" + u.Name + "] is online\n"
			this.SendMsg(onlineMsg)
		}
		this.Server.mapLock.Unlock()
	} else if len(msg) > 7 && msg[:7] == "rename|" {
		newName := strings.Split(msg, "|")[1]

		this.Server.mapLock.Lock()
		_, ok := this.Server.OnlineMap[newName]
		if ok {
			this.SendMsg("Name aready exists!\n")
		} else {
			// delete old name, then set new one
			delete(this.Server.OnlineMap, this.Name)
			this.Name = newName
			this.Server.OnlineMap[newName] = this
			this.SendMsg("Update success :" + newName + "\n")
		}
		this.Server.mapLock.Unlock()

	} else if len(msg) > 4 && msg[:3] == "to|" {
		remoteName := strings.Split(msg, "|")[1]
		if remoteName == "" {
			this.SendMsg("Message format is incorrect!Please use: 'to|userName|message'\n")
			return
		}
		remoteUser, ok := this.Server.OnlineMap[remoteName]
		if !ok {
			this.SendMsg("User does not exist!\n")
			return
		}
		sendMsg := strings.Split(msg, "|")[2]
		if sendMsg == "" {
			this.SendMsg("No message content, please re-enter\n")
			return
		}
		remoteUser.SendMsg(this.Name + " said to you: " + sendMsg + "\n")

	} else {
		// broadcast msg
		this.Server.Broadcast(this, msg)
	}
}

// goroutine: listen user chanel, send message to client
func (this *User) ListenMessage() {
	for {
		msg := <-this.C
		this.conn.Write([]byte(msg + "\n"))
	}
}
